# -*- coding: utf-8 -*-
"""
    share.validators
    ~~~~~~~~~~~~~~~~~

    字段校验模块
"""


from peewee import DJANGO_MAP

from pyshare.const.lang.tips_info import TipsInfo
from pyshare.dal.dal_adapters import USE_DATA_LAYER, DATA_LAYER_CHAOS
import pyshare.utils.json_utils as json
from pyshare.utils.traceback_utils import print_exc


class ValidationError(ValueError):
    """
    当验证失败的时候抛出异常
    """

    def __init__(self, message='', *args, **kwargs):
        super(ValidationError, self).__init__(message, *args, **kwargs)


class ModelFilter(object):
    """
    ORM的filter校验

    格式为`{Field__OP: value}`. Field为Model的字段
    OP支持gt, is, ne, in, regexp, eq, like, gte, ilike, lt, lte

    :param model: ORM的Model
    :type model: Model
    :param str message: 错误提示
    """

    def __init__(self, model, message=None):
        self._model = model
        self._message = message

    def __call__(self, value):
        message = self._message

        if message is None:
            message = TipsInfo.GlobalKeys.paramError

        if not isinstance(value, dict):
            raise ValidationError(message)

        for flt, _ in value.iteritems():
            if '__' not in flt:
                raise ValidationError(message)

            flt_split = flt.split('__')
            if len(flt_split) != 2:
                raise ValidationError(message)

            if USE_DATA_LAYER == DATA_LAYER_CHAOS:
                if not self._model.__dict__.get(flt_split[0]):
                    raise ValidationError(message)
            else:
                if not hasattr(self._model, flt_split[0]):
                    raise ValidationError(message)

            if flt_split[1] not in DJANGO_MAP.keys():
                raise ValidationError(message)


class CheckLength(object):
    """
    ORM字符串字段长度校验

    :param model: ORM的Model
    :type model: Model
    :param str message: 错误提示
    """

    def __init__(self, model, message=None):
        self._model = model
        self._message = message

    def field_length_chaos(self, field):
        f = self._model.__dict__.get(field, None)
        if not f:
            return 0
        return getattr(f, 'max_length', 0)

    def field_length_peewee(self, field):
        if not getattr(self._model, field, None):
            return 0
        return getattr(getattr(self._model, field), 'max_length')

    def __call__(self, field, value):

        # 值的长度
        try:
            if isinstance(value, dict) or isinstance(value, list):
                l = value and len(json.dumps(value, ensure_ascii=False)) or 0
            else:
                l = value and len(value) or 0
        except Exception as e:
            l = value and len(value) or 0
            print_exc(e)
        # 字段长度的取值区间
        if USE_DATA_LAYER == DATA_LAYER_CHAOS:
            str_max = self.field_length_chaos(field)
        else:
            str_max = self.field_length_peewee(field)

        if l > str_max:
            message = self._message

            if message is None:
                message = u'字段"{}"超出最大长度{}, 当前长度{}'

            raise ValidationError(message.format(field, str_max, l))


model_filter = ModelFilter
check_length = CheckLength
